<?php
/**
 * Created by Administrator
 * User: longli
 * Date: 2020/08/21
 * Time: 19:24
 * @link http://www.lmterp.cn
 */

namespace app\common\service\import;

use app\common\library\Tools;
use app\common\model\Category;
use app\common\model\Producer;
use app\common\model\ProductBrand;
use app\common\model\ProductPurchase;
use app\common\model\ProductSpec;
use app\common\model\ProductStore;
use app\common\model\ProductUnit;
use app\common\model\Warehouse;
use app\common\service\product\ProductService;

/**
 * 导入产品
 * Class Product
 * @package app\common\service\import
 */
class Product extends BaseImport
{
    /**
     * 是否更新产品, 默认为添加产品
     * @var bool
     */
    private $isUpdate;

    /**
     * 是否为每个产品的首行
     * @var bool
     */
    private $isFirst;

    /**
     * 交换键值后读入头信息
     * @var array
     */
    protected $hproduct = [];

    /**
     * 原读入头信息
     * @var array
     */
    protected $eproduct = [];

    /**
     * 不录入的字段
     * @var array
     */
    protected $excludeField = [
        'product.create_by', 'store.lock_store', 'product.default_purchase', 'product.price', 'product.create_time'
    ];

    public function init()
    {
        $this->eproduct = (new \app\common\service\export\Product())->getHeader() + ['product.warehouse_id' => '仓库'];
        $this->hproduct = array_flip($this->eproduct);
    }

    /**
     * @inheritDoc
     */
    protected function write()
    {
        foreach($this->buildProductData() as $product)
        {
            ProductService::getInstance()->addProduct($product);
        }
    }

    /**
     * 构建导入产品数据格式
     * @return array
     * @date 2020/09/11
     * @author longli
     */
    protected function buildProductData()
    {
        $tempProduct = [];
        $next = null;
        foreach($this->getData() as & $item)
        {
            // 过滤不录入字段
            foreach($this->excludeField as $k)
            {
                unset($item['product'][$k], $item['purchase'][$k]);
                if(isset($item['store'][0]))
                {
                    foreach($item['store'] as & $st)
                    {
                        unset($st[$k]);
                        if($this->isUpdate) unset($st['store.sku']);
                    }
                }
                else
                {
                    unset($item['store'][$k]);
                    if($this->isUpdate) unset($item['store']['store.sku']);
                }
            }
            if($this->isUpdate) unset($item['store.stock']);
            if(!empty($item['product'])) $this->transform($item['product']);
            if(!empty($item['store'])) $this->transform($item['store']);
            if(!empty($item['purchase'])) $this->transform($item['purchase']);

            // 更新数据组装
            if($this->isUpdate)
            {
                if(!empty($item['product']['product.product_id'])) $next = $item['product']['product.product_id'];
                if($next === null) continue;
                if(!empty($item['product']['product.product_id'])) $tempProduct[$next]['product'] = $item['product'];
                if(!empty($item['store'])) $tempProduct[$next]['store'][] = $item['store'];
                if(!empty($item['purchase'])) $tempProduct[$next]['purchase'][] = $item['purchase'];
                continue;
            }
            else
            {
                $tempProduct[] = $item;
            }
        }

        foreach($tempProduct as & $item)
        {
            $dks = array_keys($item);
            $images = $attrs = [];
            $item += $item['product'];
            if(!empty($item['product.image_url'])) $images[] = $item['product.image_url'];
            if(!empty($item['product.image_list'])) $images = array_merge($item['product.image_list'], $images);
            if(isset($item['store']) && is_array($item['store']))
            {
                $temp = [];
                for($i = 0; $i < count($item['store']); $i++)
                {

                    if(!empty($item['store'][$i]['store.image_url'])) $images[] = $item['store'][$i]['store.image_url'];
                    if(!empty($item['store'][$i]['store.color'])) $attrs[] = $item['store'][$i]['store.color'];
                    if(!empty($item['store'][$i]['store.attr'])) $attrs[] = $item['store'][$i]['store.attr'];
                    foreach(array_keys($item['store'][0]) as $k)
                    {
                        $temp[$k][$i] = $item['store'][$i][$k];
                    }
                    if(!$this->isUpdate) $temp['stock.stock'] = $temp['store.stock'];
                }
                if(!empty($temp))  $item += $temp;
            }
            if(isset($item['purchase'])  && is_array($item['purchase']))
            {
                $temp = [];
                if($this->isUpdate)
                {
                    $count = count($item['purchase']);
                    $keys = array_keys($item['purchase'][0]);
                }
                else
                {
                    $count = 1;
                    $keys = array_keys($item['purchase']);
                }
                for($i = 0; $i < $count; $i++)
                {
                    foreach($keys as $k)
                    {
                        $temp[$k][$i] = !$this->isUpdate ? $item['purchase'][$k] : $item['purchase'][$i][$k];
                    }
                }
                if(!empty($temp))  $item += $temp;
            }
            foreach($dks as $k)unset($item[$k]);

            // 持续处理
            if(!empty($images)) $item += ['image.images' => array_unique($images)];
            if(!empty($attrs)) $item += ['attr.values' => array_column(ProductSpec::getByNames($attrs)->toArray(),'spec_id')];
            if(!$this->isUpdate) $item['product.status'] = \app\common\model\Product::STATUS_NEW;
            if(!$this->isUpdate && !empty($item['product.warehouse_id'])) $item['stock.warehouse_id'] = [$item['product.warehouse_id']];
        }
       return $tempProduct;
    }

    /**
     * @inheritDoc
     */
    protected function validate(&$row = [], $key = 0)
    {
        if(count(Tools::visibleArray($this->eproduct, $row)) == 0) return "未按模板导入";
        $row = Tools::replaceArrayKey($this->hproduct, $row);
        // 判断更新还是新增
        if(!$this->isUpdate && !empty($row['product.product_id'])) $this->isUpdate = true;
        if($this->isUpdate) $this->isFirst = $key == 0 || !empty($row['product.product_id']);

        $parseData = ProductService::getInstance()->parseRequestData($row, 1);
        $valiPro = !$this->isUpdate || $this->isFirst ? $this->validateProduct($parseData['product']) : true;
        $valPur = $this->validatePurchase($parseData['purchase']);

        if($this->isUpdate)
        {
            $valSt = !empty($parseData['store']['store.sku']) ? $this->validateStore($parseData['store']) : true;
        }
        else
        {
            // 新增需要特殊处理
            $parseData['store'] = $this->parseStore($parseData['store']);
            $stRet = [];
            foreach($parseData['store']  as $s) if(($vt = $this->validateStore($s)) !== true) $stRet[] = $vt;
            $valSt = !empty($stRet) ? join(', ', $stRet) : true;
        }
        if($valiPro === true && $valPur === true && $valSt === true)
        {
            unset($parseData['other']);
            $row = $parseData;
            return true;
        }
        $msg = "";
        if($valiPro !== true) $msg .= "$valiPro, ";
        if($valPur !== true) $msg .= "$valPur, ";
        if($valSt !== true) $msg .= "$valSt, ";
        return $msg;
    }

    /**
     * 新增商品时解析变体信息，变体属性和sku，只能二选一
     * @param array $store 变体数据
     * @return array 解析后数据
     * @date 2020/09/11
     * @author longli
     */
    protected function parseStore($store = [])
    {
        if(!empty($store['store.sku'])) return [$store];
        $stt = [];
        if(!empty($store['store.attr']))
        {
            $attr = array_map(function($item)
            {
               return strtoupper($item);
            }, $this->filterData($store['store.attr']));
            if(!empty($attr)) $stt['attr'] = $attr;
        }

        if(!empty($store['store.color']))
        {
            $color = $this->filterData($store['store.color']);
            if(!empty($color)) $stt['color'] = $color;
        }
        if(empty($stt)) return [$store];
        $ret = $tempAttr = [];
        if(isset($stt['color']) && isset($stt['attr']))
        {
            foreach($stt['color'] as $c)
            {
                foreach($stt['attr'] as $a) $tempAttr[] = ['store.attr' => $a, 'store.color' => $c];
            }
        }
        else if(isset($stt['color']))
        {
            foreach($stt['color'] as $c) $tempAttr[] = ['store.attr' => '', 'store.color' => $c];

        }
        else if(isset($stt['attr']))
        {
            foreach($stt['attr'] as $a) $tempAttr[] = ['store.attr' => $a, 'store.color' => ''];
        }

        $skus = ProductService::getInstance()->generateSameSku(count($tempAttr));
        foreach($tempAttr as $i => $item)
        {
            $item['store.sku'] = is_array($skus) ? $skus[$i] : $skus;
            $ret[] = $item + $store;
        }
        return $ret;
    }

    /**
     * 过虑字符信息
     * @param string $str 需要处理的字符串
     * @return array 处理结果
     * @date 2020/09/11
     * @author longli
     */
    private function filterData($str)
    {
       return array_unique(array_filter(Tools::trim(explode(',', str_replace(['，'], ',', $str)))));
    }

    /**
     * 验证商品
     * @param array $product 商品信息
     * @return bool|string
     * @date 2020/09/11
     * @author longli
     */
    protected function validateProduct(& $product = [])
    {
        $error = [];
        $reqField = ['product.brand', 'product.category_id', 'product.name_ch', 'product.image_list'];
        if(($req = $this->requireField($product, $reqField, $this->eproduct)) !== true) $error = array_merge($error, $req);
        $validateNum = ['product.product_id', 'product.price', 'product.declare_price', 'product.hot'];
        if(($valiNum = $this->validateNumber($product, $validateNum, $this->eproduct)) !== true) $error = array_merge($error, $valiNum);
        if(($valiImg = $this->validateImage($product, ['product.image_url'], $this->eproduct)) !== true) $error = array_merge($error, $valiImg);
        if(empty($error))
        {
            if(!empty($product['product.image_list']))
            {
               $product['product.image_list'] = $this->filterData($product['product.image_list']);
               foreach($product['product.image_list'] as $image)
               {
                   if(($valiImg = $this->validateImage(['product.image_list' => $image], ['product.image_list'], $this->eproduct)) !== true) $error = array_merge($error, $valiImg);
               }
            }
            if(!ProductBrand::hasBrand($product['product.brand'])) $error[] = "品牌【{$product['product.brand']}】不存在";
            // 处理多级分类
            if(Tools::contains($product['product.category_id'], '>'))
            {
                foreach(explode('>', $product['product.category_id']) as $citem)
                {
                    $citem = trim($citem);
                    if(!Category::hasByName($citem)) $error[] = "分类【{$citem}】不存在";
                }
            }
            else
            {
                if(!Category::hasByName($product['product.category_id'])) $error[] = "分类【{$product['product.category_id']}】不存在";
                if(!Category::checkUnique($product['product.category_id'])) $error[] = "分类【{$product['product.category_id']}】不是唯一";
            }
            if(!empty($product['product.unit_id']) && !ProductUnit::hasUnit($product['product.unit_id'])) $error[] = "计量单位【{$product['product.unit_id']}】不存在";
            if(!empty($product['product.status']) && !in_array($product['product.status'], \app\common\model\Product::$STATUS)) $error[] = "状态【{$product['product.status']}】不合法";
            if(!empty($product['product.warehouse_id']) && !Warehouse::hasByName($product['product.warehouse_id'])) $error[] = "仓库【{$product['product.category_id']}】不存在";
        }
        return !empty($error) ? join(", ", $error) : true;
    }

    /**
     * 验证商品变体
     * @param array $store 变体信息
     * @return bool|string
     * @date 2020/09/11
     * @author longli
     */
    protected function validateStore(& $store = [])
    {
        $error = [];
        if(!$this->isUpdate && ProductStore::hasSku($store['store.sku'])) $error[] = "SKU【{$store['store.sku']}】已存在";
        if(!$this->isUpdate && ($reqOr = $this->requireOr($store, ['store.attr', 'store.color'], $this->eproduct)) !== true) $error[] = join(" 或 ", $reqOr) . "必填一个";
        // 验证数字
        $validateNum = ['store.store', 'store.store_id', 'store.length', 'store.width',
            'store.height', 'store.weight', 'store.package_weight', 'store.price', 'store.lock_store',
            'store.purchase_store',
        ];
        if(($valiNum = $this->validateNumber($store, $validateNum, $this->eproduct)) !== true) $error = array_merge($error, $valiNum);
        if(($valiImg = $this->validateImage($store, ['store.image_url'], $this->eproduct)) !== true) $error = array_merge($error, $valiImg);
        if(empty($error))
        {
           if(($req = $this->requireField($store, ['store.sku'], $this->eproduct)) !== true) $error = array_merge($error, $req);
           if(!empty($store['store.attr']) && !ProductSpec::hasByName($store['store.attr'])) $error[] = "属性【{$store['store.attr']}】不存在";
           if(!empty($store['store.color']) && !ProductSpec::hasByName($store['store.color'])) $error[] = "颜色【{$store['store.color']}】不存在";
        }

        return !empty($error) ? join(", ", $error) : true;
    }

    /**
     * 验证商品采购信息
     * @param array $purchase 商品采购信息
     * @return bool|string
     * @date 2020/09/11
     * @author longli
     */
    protected function validatePurchase(& $purchase = [])
    {
        $error = [];
        $validateNum = ['purchase.pp_id', 'purchase.min_qty', 'purchase.price'];
        if(($valiNum = $this->validateNumber($purchase, $validateNum, $this->eproduct)) !== true) $error = array_merge($error, $valiNum);
        if(($valiUrl = $this->validateUrl($purchase, ['purchase.url'], $this->eproduct)) !== true) $error = array_merge($error, $valiUrl);
        if(!empty($purchase['purchase.producer_id']) && !Producer::hasByName($purchase['purchase.producer_id'])) $error[] = "供应商{$purchase['purchase.producer_id']}不存在";
        if(!empty($purchase['purchase.status']) && !in_array($purchase['purchase.status'], ProductPurchase::$STATUS)) $error[] = "采购状态【{$purchase['purchase.status']}】不合法";
        if(!empty($purchase['purchase.type']) && !in_array($purchase['purchase.type'], Producer::$LINE_TYPE)) $error[] = "采购类型【{$purchase['purchase.type']}】不合法";
        if(!empty($purchase['purchase.is_default']) && !in_array($purchase['purchase.is_default'], ProductPurchase::$IS_STATUS)) $error[] = "默认采购【{$purchase['purchase.is_default']}】不合法";
        return !empty($error) ? join(", ", $error) : true;
    }

    /**
     * 数据转换为可写入数据库的格式
     * @param array $row 需要转换的数据
     * @date 2020/09/11
     * @author longli
     */
    protected function transform(& $row = [])
    {
        if(isset($row[0]))
        {
            foreach($row as & $r) $this->transform($r);
        }
        // 商品
        if(!empty($row['product.brand'])) $row['product.brand'] = ProductBrand::getByName($row['product.brand'])->brand_id;
        if(!empty($row['product.category_id']))
        {
            if(Tools::contains($row['product.category_id'], '>'))
            {
                $cates = explode('>', $row['product.category_id']);
                $t = Category::with(['son' => function($query)use($cates)
                {
                    count($cates) == 3
                     ? $query->with(['son' => function($query)use($cates){$query->where("name", $cates[2]);}])->where("name", $cates[1])
                     : $query->where("name", $cates[1]);
                }])->get(['name' => $cates[0]]);
                while(!$t->son->isEmpty()) $t = $t->son[0];
                $row['product.category_id'] = $t->cate_id;
            }
            else
            {
                $row['product.category_id'] = Category::getByName($row['product.category_id'])->cate_id;
            }
        }
        if(!empty($row['product.unit_id'])) $row['product.unit_id'] = ProductUnit::getByName($row['product.unit_id'])->unit_id;
        if(!empty($row['product.status'])) $row['product.status'] = array_flip(\app\common\model\Product::$STATUS)[$row['product.status']];
        if(!empty($row['product.warehouse_id'])) $row['product.warehouse_id'] = Warehouse::getByName($row['product.warehouse_id'])->warehouse_id;

        // 采购
        if(!empty($row['purchase.producer_id'])) $row['purchase.producer_id'] = Producer::getByName($row['purchase.producer_id'])->producer_id;
        if(!empty($row['purchase.status'])) $row['purchase.status'] = array_flip(ProductPurchase::$STATUS)[$row['purchase.status']];
        if(!empty($row['purchase.type'])) $row['purchase.type'] = array_flip(Producer::$LINE_TYPE)[$row['purchase.type']];
        if(!empty($row['purchase.is_default'])) $row['purchase.is_default'] = array_flip(ProductPurchase::$IS_STATUS)[$row['purchase.is_default']];
    }

    public function setIsUpdate($isUpdate)
    {
        $this->isUpdate = $isUpdate;
    }

    public function getIsUpdate()
    {
        return $this->isUpdate;
    }
}